package com.maxcion.scalelayoutmanager

import android.graphics.Rect
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class ScaleLayoutManager : RecyclerView.LayoutManager() {

    private var itemHeight: Int = 0
    private var itemWidth: Int = 0
    private var mHorizontalScrollX = 0

    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
    }

    override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
        recycler?.let {
            mHorizontalScrollX = 0
            if (itemCount == 0) {
                detachAndScrapAttachedViews(recycler)

                return
            }


            fillHorizontal(recycler, state)
        }
    }

    private fun fillHorizontal(
        recycler: RecyclerView.Recycler,
        state: RecyclerView.State?
    ) {

        detachAndScrapAttachedViews(recycler)
        if (mHorizontalScrollX == 0) {
            val view = recycler.getViewForPosition(0)
            addView(view)
            measureChildWithMargins(view, 0, 0)
            var rect = Rect()
            getDecoratedBoundsWithMargins(view, rect)
            itemWidth = view.measuredWidth
            itemHeight = view.measuredHeight


        }

        fillChild(recycler)

        recycleChildren(recycler)
    }

    private fun fillChild(recycler: RecyclerView.Recycler) {
        val offsetX = mHorizontalScrollX % itemWidth
        for ((childIndex, index) in (mHorizontalScrollX / itemWidth until itemCount).withIndex()) {
            val child = recycler.getViewForPosition(index)

            addView(child)
            measureChildWithMargins(child, 0, 0)

            val left = -offsetX + childIndex * itemWidth
            val right = left + itemWidth
            layoutDecoratedWithMargins(child, left, 0, right, itemHeight)

            val fraction = when (child.left) {
                in 0..itemWidth -> {
                    (itemWidth - child.left) / itemWidth.toFloat() * 0.1f + 0.9f
                }
                in -itemWidth..0 -> {
                    child.left / itemWidth.toFloat() * 0.1f + 1
                }
                else -> {
                    0.9f
                }
            }
            child.scaleX = fraction
            child.scaleY = fraction
            if (right >= width) {
                break
            }


        }
    }

    override fun canScrollHorizontally(): Boolean {
        return true
    }

    override fun canScrollVertically(): Boolean {
        return false
    }

    override fun scrollHorizontallyBy(
        dx: Int,
        recycler: RecyclerView.Recycler?,
        state: RecyclerView.State?
    ): Int {
        var newDx = dx
        if (mHorizontalScrollX <= 0 && newDx < 0) {
            newDx = 0
        }

        if (mHorizontalScrollX >= getMaxScrollX() && newDx > 0) {
            newDx = 0
        }

        if (mHorizontalScrollX + newDx <= 0) {
            newDx = -mHorizontalScrollX
        }

        if (mHorizontalScrollX + newDx > getMaxScrollX()) {
            newDx = getMaxScrollX() - mHorizontalScrollX
        }

        mHorizontalScrollX += newDx
        if (newDx != 0)
            fillHorizontal(recycler!!, state)
        return newDx
    }

    private fun getMaxScrollX() = itemWidth * itemCount - width

    private fun recycleChildren(recycler: RecyclerView.Recycler) {
        val scrapList: List<RecyclerView.ViewHolder> = recycler.getScrapList()
        for (i in scrapList.indices) {
            if (i < scrapList.size) {
                val holder = scrapList[i]
                removeAndRecycleView(holder.itemView, recycler)
            }
        }
    }

}